﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;
using Microsoft.ServiceBus;
using nwrole.plugin;

namespace nwrole.lib {
    public class Orchestrator {
        private ServiceHost serviceHost;
        private OrchestratorService orchestratorService;

        private ServiceHost ctrlServiceHost;
        private OrchestratorCtrlService orchestratorCtrlService;

        /// <summary>
        /// Starts an orchestrator. It creates 3 endpoints over Azure Service Bus with the contracts; IOrchestratorContract, IOrchestratorWebsiteContract and IOrchestratorCtrlContract
        /// </summary>
        /// <param name="sbIssuerName">Service Bus issuer name </param>
        /// <param name="sbIssuerSecret">Service Bus issuer secret</param>
        public void Start(string sbIssuerName, string sbIssuerSecret) {
            ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.AutoDetect;

            //Console.WriteLine("Starting place {0}...", place.Folder.Name);

            TransportClientEndpointBehavior sharedSecretServiceBusCredential = new TransportClientEndpointBehavior();
            sharedSecretServiceBusCredential.TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(sbIssuerName, sbIssuerSecret);
            /*sharedSecretServiceBusCredential.CredentialType = TransportClientCredentialType.SharedSecret;
            sharedSecretServiceBusCredential.Credentials.SharedSecret.IssuerName = "owner";
            sharedSecretServiceBusCredential.Credentials.SharedSecret.IssuerSecret = "Km+nny0pbfguRgaHjslR/IkWpUprTzgrJYZwvXiCJwU=";*/

            Uri clientServiceBaseAddress = ServiceBusEnvironment.CreateServiceUri("sb", "nwrole", "nwrole/Orchestrator");
            Uri ctrlClientServiceBaseAddress = ServiceBusEnvironment.CreateServiceUri("sb", "nwrole", "nwrole/OrchestratorCtrl");
            Uri websiteServiceBaseAddress = ServiceBusEnvironment.CreateServiceUri("sb", "nwrole", "orchestrator/website");

            orchestratorService = new OrchestratorService();
            orchestratorService.OrchestratorLog(LogLevel.Info, "OrchestratorService starting", null);
            serviceHost = new ServiceHost(orchestratorService, clientServiceBaseAddress);
            try {
                IEndpointBehavior serviceRegistrySettings = new ServiceRegistrySettings(DiscoveryType.Public);

                ContractDescription clientContractDescription = ContractDescription.GetContract(typeof(IOrchestratorContract), typeof(OrchestratorService));
                ServiceEndpoint clientServiceEndPoint = new ServiceEndpoint(clientContractDescription);
                clientServiceEndPoint.Address = new EndpointAddress(clientServiceBaseAddress);
                //clientServiceEndPoint.Binding = new NetTcpRelayBinding();
                clientServiceEndPoint.Binding = new NetTcpRelayBinding(EndToEndSecurityMode.Transport, RelayClientAuthenticationType.RelayAccessToken);
                serviceHost.Description.Endpoints.Add(clientServiceEndPoint);

                ContractDescription websiteContractDescription = ContractDescription.GetContract(typeof(IOrchestratorWebsiteContract), typeof(OrchestratorService));
                ServiceEndpoint websiteServiceEndPoint = new ServiceEndpoint(websiteContractDescription);
                websiteServiceEndPoint.Address = new EndpointAddress(websiteServiceBaseAddress);
                websiteServiceEndPoint.Binding = new NetTcpRelayBinding(EndToEndSecurityMode.Transport, RelayClientAuthenticationType.RelayAccessToken);
                serviceHost.Description.Endpoints.Add(websiteServiceEndPoint);

                foreach (ServiceEndpoint endpoint in serviceHost.Description.Endpoints) {
                    endpoint.Behaviors.Add(serviceRegistrySettings);
                    endpoint.Behaviors.Add(sharedSecretServiceBusCredential);
                }

                serviceHost.Open();

                //Console.WriteLine("Service address: {0}", baseAddress);
            } catch (CommunicationException ce) {
                //Console.WriteLine("An exception occurred with place {0}: {1}", place.Folder.Name, ce.Message);
                orchestratorService.OrchestratorLog(LogLevel.Error, "Unable to init ServiceBus for OrchestratorService", ce);
                serviceHost.Abort();
            }

            orchestratorCtrlService = new OrchestratorCtrlService(orchestratorService);
            ctrlServiceHost = new ServiceHost(orchestratorCtrlService, ctrlClientServiceBaseAddress);
            try {
                IEndpointBehavior serviceRegistrySettings = new ServiceRegistrySettings(DiscoveryType.Public);

                ContractDescription ctrlClientContractDescription = ContractDescription.GetContract(typeof(IOrchestratorCtrlContract), typeof(OrchestratorCtrlService));
                ServiceEndpoint ctrlClientServiceEndPoint = new ServiceEndpoint(ctrlClientContractDescription);
                ctrlClientServiceEndPoint.Address = new EndpointAddress(ctrlClientServiceBaseAddress);
                //ctrlClientServiceEndPoint.Binding = new NetTcpRelayBinding();
                ctrlClientServiceEndPoint.Binding = new NetTcpRelayBinding(EndToEndSecurityMode.Transport, RelayClientAuthenticationType.RelayAccessToken);
                ctrlServiceHost.Description.Endpoints.Add(ctrlClientServiceEndPoint);

                foreach (ServiceEndpoint endpoint in ctrlServiceHost.Description.Endpoints) {
                    endpoint.Behaviors.Add(serviceRegistrySettings);
                    endpoint.Behaviors.Add(sharedSecretServiceBusCredential);
                }

                ctrlServiceHost.Open();

                //Console.WriteLine("Service address: {0}", baseAddress);
            } catch (CommunicationException ce) {
                //Console.WriteLine("An exception occurred with place {0}: {1}", place.Folder.Name, ce.Message);
                orchestratorService.OrchestratorLog(LogLevel.Error, "Unable to init ServiceBus for OrchestratorCtrlService", ce);
                ctrlServiceHost.Abort();
            }
        }

        public void Stop() {
            if(ctrlServiceHost != null) {
                orchestratorCtrlService.Stop();
                ctrlServiceHost.Close();
                serviceHost = null;
                orchestratorCtrlService = null;
            }

            if (serviceHost != null) {
                orchestratorService.Stop();
                serviceHost.Close();
                serviceHost = null;
                orchestratorService = null;
            }
        }
    }
}
